/**
 * 
 */
package dt.inlee.system.service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MethodInvoker;

import dt.inlee.common.exception.FrameworkException;
import dt.inlee.common.scheduler.MethodInvokingJobBean;
import dt.inlee.domain.JobDetails;
import dt.inlee.system.dao.JobDetailsDao;
import dt.inlee.system.vo.JobDetailsBean;
import dt.inlee.system.vo.TriggerBean;

/**
 * 功能说明：定时任务调度业务层
 * @作者： cnoot
 * 创建日期： 2010-5-24
 */
//@Service("schedulerService")
public class SchedulerService {
	//@Resource(name = "quartzScheduler")
	private Scheduler quartzScheduler;
	@Resource(name = "jobDetailDao")
	private JobDetailsDao jobDetailDao;
	//触发器执行状态 1 为停止 0为正常
	private static String PASUED = "停止";
	private static String NORMAL = "正常";
	private static final Logger logger = LoggerFactory.getLogger(SchedulerService.class);

	public void setQuartzScheduler(Scheduler quartzScheduler) {
		this.quartzScheduler = quartzScheduler;
	}

	public void setJobDetailDao(JobDetailsDao jobDetailDao) {
		this.jobDetailDao = jobDetailDao;
	}

	/**
	 * 查询所有定时任务
	 * @return
	 * @throws FrameworkException
	 * @throws SchedulerException 
	 */
	@SuppressWarnings("unchecked")
	public List<JobDetailsBean> findJobDetails() throws FrameworkException, SchedulerException {
		logger.debug("findJobDetails()..");
		List<JobDetailsBean> jdb = new ArrayList<JobDetailsBean>();
		List<JobDetails> details = jobDetailDao.findAll(JobDetails.class);
		for (JobDetails jd : details) {
			JobDetailsBean jobDetails = new JobDetailsBean();
			jobDetails.setId(jd.getId());
			jobDetails.setBeanId(jd.getBeanId());
			jobDetails.setDescription(jd.getDescription());
			jobDetails.setJobName(jd.getJobName());
			jobDetails.setExecuteMethod(jd.getExecuteMethod());
			jobDetails.setTriggerSum(this.findTriggerByJobName(jd.getId()).size());
			jdb.add(jobDetails);
		}
		return jdb;
	}

	/**
	 * 新增定时任务
	 * @param jobDetailsBean
	 * @throws FrameworkException
	 * @throws SchedulerException 
	 */
	@Transactional
	public void addJobDetail(JobDetailsBean jobDetailsBean) throws FrameworkException, SchedulerException {
		logger.debug("addJobDetail()..jobDetailsBean:" + jobDetailsBean);
		logger.debug("getBeanId:" + jobDetailsBean.getBeanId());
		logger.debug("getExecuteMethod:" + jobDetailsBean.getExecuteMethod());
		logger.debug("getJobName:" + jobDetailsBean.getJobName());
		JobDetails jd = conversionJobDetailsBean(jobDetailsBean);
		this.jobDetailDao.save(jd);
		JobDetail jobDetail = this.conversionJobDetails(jd);
		this.quartzScheduler.addJob(jobDetail, true);
	}

	/**
	 * 修改定时任务
	 * @param jobDetails
	 * @throws FrameworkException
	 * @throws SchedulerException 
	 */
	@Transactional
	public void updateJobDetail(JobDetailsBean jobDetailsBean) throws FrameworkException, SchedulerException {
		logger.debug("updateJobDetail(),jobDetailsBean:" + jobDetailsBean);
		JobDetails jd = this.findJobDetailsById(jobDetailsBean.getId());
		jd.setDescription(jobDetailsBean.getDescription());
		jd.setBeanId(jobDetailsBean.getBeanId());
		jd.setExecuteMethod(jobDetailsBean.getExecuteMethod());
		jd.setJobName(jobDetailsBean.getJobName());
		this.jobDetailDao.update(jd);
	}

	/**
	 * 根据定时任务ID取得其详细信息
	 * @param id
	 * @return
	 * @throws FrameworkException
	 */
	public JobDetails findJobDetailsById(String id) throws FrameworkException {
		logger.debug("findJobDetailsById(),id:" + id);
		return (JobDetails) jobDetailDao.get(JobDetails.class, id);
	}

	/**
	 * 停止触发器
	 * @param triggerNames
	 * @throws SchedulerException
	 */
	@Transactional
	public void pauseTriggers(String[] triggerNames) throws SchedulerException {
		logger.debug("pauseTriggers(),triggerNames:" + triggerNames);
		for (String triggerName : triggerNames) {
			this.quartzScheduler.pauseTrigger(triggerName, Scheduler.DEFAULT_GROUP);
		}
	}

	/**
	 * 重启触发器
	 * @param triggerNames
	 * @throws SchedulerException
	 */
	@Transactional
	public void resumeTrigger(String[] triggerNames) throws SchedulerException {
		logger.debug("resumeTrigger(),triggerNames:" + triggerNames);
		for (String triggerName : triggerNames) {
			this.quartzScheduler.resumeTrigger(triggerName, Scheduler.DEFAULT_GROUP);
		}
	}

	/**
	* 删除触发器
	* @param triggerNames
	* @throws SchedulerException
	*/
	@Transactional
	public void removeTriggers(String[] triggerNames) throws SchedulerException {
		logger.debug("removeTriggers(),triggerNames:" + triggerNames);
		for (String triggerName : triggerNames) {
			this.quartzScheduler.pauseTrigger(triggerName, Scheduler.DEFAULT_GROUP);
			this.quartzScheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP);
		}
	}

	/**
	 * 删除定时任务
	 * @param jobNames
	 * @throws SchedulerException
	 * @throws FrameworkException 
	 */
	@Transactional
	public boolean deleteJob(String id) throws SchedulerException, FrameworkException {
		logger.debug("deleteJob()..jobDetailsBean:" + id);
		this.jobDetailDao.deleteById(JobDetails.class, id);
		this.quartzScheduler.pauseJob(id, Scheduler.DEFAULT_GROUP);
		return this.quartzScheduler.deleteJob(id, Scheduler.DEFAULT_GROUP);
	}

	/**
	 * 给指定的计划任务新增触发器(Trigger)
	 * @param jobId
	 * @param tb
	 * @throws SchedulerException
	 * @throws FrameworkException
	 * @throws ClassNotFoundException
	 * @throws NoSuchMethodException
	 * @throws ParseException 
	 */
	@Transactional
	public void addTriggerToJobDetail(String jobName, TriggerBean tb) throws SchedulerException, FrameworkException,
			ClassNotFoundException, NoSuchMethodException, ParseException {
		logger.debug("addTriggerToJobDetail()");
		logger.debug("addTriggerToJobDetail()...getExeType:" + tb.getExeType());
		Trigger trigger = null;
		switch (tb.getExeType()) {
		//每月执行
		case 1:
			trigger = TriggerUtils.makeMonthlyTrigger(tb.getDayOfMonth(), tb.getHour(), tb.getMinute());
			break;
		//每周执行
		case 2:
			trigger = TriggerUtils.makeWeeklyTrigger(tb.getDayOfWeek(), tb.getHour(), tb.getMinute());
			break;
		//每天执行
		case 3:
			trigger = TriggerUtils.makeDailyTrigger(tb.getHour(), tb.getMinute());
			break;
		//按小时
		case 4:
			if (stringToInt(tb.getRepeatCount()) != 0 && stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeHourlyTrigger(stringToInt(tb.getRepeatInterval()), stringToInt(tb
						.getRepeatCount()));
			} else if (stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeHourlyTrigger(tb.getRepeatInterval());
			} else {
				trigger = TriggerUtils.makeHourlyTrigger();
			}
			break;
		//按分钟
		case 5:
			if (stringToInt(tb.getRepeatCount()) != 0 && stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeMinutelyTrigger(stringToInt(tb.getRepeatInterval()), stringToInt(tb
						.getRepeatCount()));
			} else if (stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeMinutelyTrigger(tb.getRepeatInterval());
			} else {
				trigger = TriggerUtils.makeMinutelyTrigger();
			}

			break;
		//按秒
		case 6:
			if (stringToInt(tb.getRepeatCount()) != 0 && stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeSecondlyTrigger(stringToInt(tb.getRepeatInterval()), stringToInt(tb
						.getRepeatCount()));
			} else if (stringToInt(tb.getRepeatInterval()) != 0) {
				trigger = TriggerUtils.makeSecondlyTrigger(tb.getRepeatInterval());
			} else {
				trigger = TriggerUtils.makeSecondlyTrigger();
			}
			break;
		//表达式
		case 7:
			logger.debug("CronTrigger()...");
			CronTrigger cronTrigger = new CronTrigger(tb.getTriggerName(), Scheduler.DEFAULT_GROUP, jobName,
					Scheduler.DEFAULT_GROUP);
			cronTrigger.setCronExpression(tb.getCronExpression());
			cronTrigger.setDescription(tb.getDescription());
			this.quartzScheduler.scheduleJob(cronTrigger);
			break;

		default:
			break;
		}
		if (trigger == null) {
			return;
		}
		if (tb.getStartTime() != null) {
			trigger.setStartTime(tb.getStartTime());
		}
		trigger.setName(tb.getTriggerName());
		trigger.setJobName(jobName);
		trigger.setGroup(Scheduler.DEFAULT_GROUP);
		trigger.setDescription(tb.getDescription());
		quartzScheduler.scheduleJob(trigger);
	}

	/**
	 * 判断定时任务名称是否重复
	 * @param id
	 * @param name 
	 * @return 存在返回 false 不存在返回 true
	 * @throws FrameworkException
	 */
	public boolean judgeJobName(String id, String name) throws FrameworkException {
		return this.jobDetailDao.judgeJobName(id, name);
	}

	/**
	 * 判断定时任务名称是否重复
	 * @param name
	 * @return 存在返回 false 不存在返回 true
	 * @throws FrameworkException
	 */
	public boolean judgeJobName(String name) throws FrameworkException {
		return this.judgeJobName(null, name);
	}

	/**
	 * 判断触发器是否存在，
	 * 
	 * @param triggerName
	 * @return 存在返回 false 不存在返回 true
	 * @throws SchedulerException 
	 * @throws FrameworkException
	 */
	public boolean judgeTriggerName(String triggerName) throws SchedulerException {
		Trigger trigger = this.quartzScheduler.getTrigger(triggerName, Scheduler.DEFAULT_GROUP);
		if (trigger == null) {
			return true;
		}
		return false;
	}

	/**
	 * 根据jobName取得其所有的触发器
	 * @param jobName
	 * @return
	 * @throws SchedulerException
	 * @throws FrameworkException 
	 */
	public List<TriggerBean> findTriggerByJobName(String jobName) throws SchedulerException, FrameworkException {
		logger.debug("findTriggerByJobName()");
		List<TriggerBean> triggerBeans = new ArrayList<TriggerBean>();
		Trigger[] triggers = quartzScheduler.getTriggersOfJob(jobName, Scheduler.DEFAULT_GROUP);
		for (Trigger trigger : triggers) {
			triggerBeans.add(conversionTrigger(trigger));
		}
		return triggerBeans;
	}

	/**
	 * 判断新增计划的 beanid 和 method 是否有效
	 * @param jobDetailsBean
	 * @return
	 * @throws SchedulerException
	 */
	public boolean judgeBeanAndMethod(JobDetailsBean jobDetailsBean) throws SchedulerException {
		logger.debug("judgeBeanAndMethod()....");
		ApplicationContext applicationContext = (ApplicationContext) this.quartzScheduler.getContext().get(
				"applicationContextKey");
		try {
			Object obj = applicationContext.getBean(jobDetailsBean.getBeanId());
			MethodInvoker mi = new MethodInvoker();
			mi.setTargetObject(obj);
			mi.setTargetMethod(jobDetailsBean.getExecuteMethod());
			mi.prepare();
			return true;
		} catch (Exception e) {
			logger.debug("不存在填写的beanId 或者 方法");
			//e.printStackTrace();
			return false;
		}
	}

	private JobDetail conversionJobDetails(JobDetails jds) {
		logger.debug("conversionJobDetails()");
		logger.debug("getJobName()" + jds.getJobName());
		JobDetail jobDetail = new JobDetail();
		jobDetail.setName(jds.getId());
		jobDetail.setDescription(jds.getDescription());
		jobDetail.setGroup(Scheduler.DEFAULT_GROUP);
		jobDetail.setDurability(true);
		jobDetail.setJobClass(MethodInvokingJobBean.class);
		logger.debug("JobDetail..jds" + jds);
		jobDetail.getJobDataMap().put("jobDetails", jds);
		return jobDetail;
	}

	@SuppressWarnings("static-access")
	private TriggerBean conversionTrigger(Trigger trigger) throws SchedulerException, FrameworkException {
		logger.debug("conversionTrigger()");
		TriggerBean triggerBean = new TriggerBean();
		triggerBean.setTriggerName(trigger.getName());
		triggerBean.setTriggerGroup(trigger.getGroup());
		triggerBean.setStartTime(trigger.getStartTime());
		triggerBean.setEndTime(trigger.getEndTime());
		triggerBean.setPreviousFireTime(trigger.getPreviousFireTime());
		triggerBean.setNextFireTime(trigger.getNextFireTime());
		triggerBean.setDescription(trigger.getDescription());
		//触发器执行状态 1 为停止 0为正常
		triggerBean
				.setState(quartzScheduler.getTriggerState(trigger.getName(), Scheduler.DEFAULT_GROUP) == 1 ? this.PASUED
						: this.NORMAL);
		return triggerBean;
	}

	private int stringToInt(String val) {
		if (val == null || val.isEmpty()) {
			return 0;
		}
		return Integer.parseInt(val);
	}

	/**
	 * @param jobDetailsBean
	 * @return
	 */
	private JobDetails conversionJobDetailsBean(JobDetailsBean jobDetailsBean) {
		JobDetails jd = new JobDetails();
		jd.setBeanId(jobDetailsBean.getBeanId());
		jd.setDescription(jobDetailsBean.getDescription());
		jd.setExecuteMethod(jobDetailsBean.getExecuteMethod());
		jd.setJobName(jobDetailsBean.getJobName());
		return jd;
	}
}
